/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package negocio;

import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.management.timer.Timer;
import persistencia.PersistenciaAlquiler;
import persistencia.PersistenciaArticulo;
import persistencia.PersistenciaCliente;
import persistencia.PersistenciaPromocion;
import persistencia.PersistenciaFactura;

/**
 * Clase controladora de alquileres y devoluciones
 * Realiza la gestión entre la Vista, las clases de Negocio y la Persistencia
 * @author JAVA
 */
public class GestionAlquiler {

    /**
     * Muestra la lista de alquileres con sus correspondientes articulos, los cuales
     * aún no han sido devueltos a través de una llamada a la Persistencia de  Alquiler
     * @param cliente sobre el que se realiza el alquiler 
     */
    public static void mostrarAlquileresPendientes(Cliente cliente) {
        List<Alquiler> lista = PersistenciaAlquiler.obtenerListaAlquileres(cliente);
        Iterator it = lista.iterator();
        System.out.println("El cliente tiene " + lista.size() + " articulo/s pendiente/s");
        while (it.hasNext()) {
            Alquiler a = (Alquiler) it.next();
            Articulo art = (Articulo) a.getArticulo();
            System.out.println(art.toString());
            System.out.println("Fecha alquiler: " + a.getFechaAlquiler());
            System.out.println("Fecha entrega: " + a.getFechaFin());
        }
    }

    /**
     * Método que llama a la Persistencia de Alquiler para obtener un articulo a partir de su id
     * Crea un objeto devolucion con el cliente y el alquiler asociado a dicha devolucion
     * Calcula el recargo en caso que exista modificando el saldo a traves de la Persistencia de Cliente
     * Por ultimo llama a la Persistencia de Alquiler y de articulo para marcar el articulo y el alquiler como devueltos
     * @param cliente que quiere devolver un artículo
     * @param codigo del artículo a devolver
     * @return 
     */
    public static int devolverArticulo(Cliente cliente, int codigo) {
        Alquiler alq = PersistenciaAlquiler.obtieneAlquiler(cliente, codigo);
        if (alq != null) {
            Devolucion dev = new Devolucion(new Date(), cliente, alq);
            float recargo = dev.getRecargo();
            //Si tengo recargo modifico el saldo del cliente
            if (recargo != 0) {
                System.out.println("Recargo descontado automaticamente de su cuenta");
                GestionMovimientos.addMovimiento(cliente, -recargo, "Recargo por alquiler");
                GestionSaldo.recargarSaldo(-recargo, cliente);
                System.out.println("Su saldo actual es de: " + cliente.getSaldo());
                PersistenciaCliente.modificaCliente(10, cliente, Float.toString(cliente.getSaldo()));
            }
            PersistenciaAlquiler.devuelveAlquiler(alq);
            PersistenciaAlquiler.devuelveArticulo(alq.getArticulo());
            return 1;
        } else {
            System.out.println("El alquiler no corresponde\n Verifique los datos");
            return 0;
        }
    }

    /**
     * Obtiene un artículo a partir de su codigo mediante la Persistencia de Articulo
     * Calcula la nueva valoración y la guarda a través de la Persistencia de Articulo
     * @param codigo del articulo sobre el que se realiza la valoracion
     * @param valoracion en formato float sobre 10
     */
    public static void valorarPelicula(int codigo, float valoracion) {
        float nuevaV;
        if (valoracion >= 0 && valoracion <= 10) {
            Articulo a = PersistenciaArticulo.obtenerArticulo(codigo);
            if (a instanceof Pelicula) {
                Pelicula p = (Pelicula) a;
                nuevaV = (p.getValoracion() + valoracion) / 2;
                p.setValoracion(nuevaV);
            }
            if (a instanceof Juego) {
                Juego j = (Juego) a;
                nuevaV = (j.getValoracion() + valoracion) / 2;
                j.setValoracion(nuevaV);
            }
            if (PersistenciaArticulo.valorarArticulo(a) == 1) {
                System.out.println("Valoracion añadida correctamente");
            }
        } else {
            System.out.println("La valoracion debe estar entre cero y diez");
        }
    }

    /**
     * Carga una lista de juegos cuya valoracion es superior a 5 a traves de Persistencia Articulo
     */
    public static void mostrarMejoresJuegos() {
        List<Articulo> lista = PersistenciaArticulo.mostrarMejorValoradas();
        if (lista.isEmpty()) {
            System.out.println("No hay novedades de este año");
        } else {
            Iterator it = lista.iterator();
            while (it.hasNext()) {
                Articulo art = (Articulo) it.next();
                if (art instanceof Juego) {
                    Juego j = (Juego) art;
                    System.out.println(j);
                }
            }
        }
    }

    /**
     * Carga una lista de peliculas cuya valoracion es superior a 5 a traves de Persistencia Articulo
     */
    public static void mostrarMejoresPeliculas() {
        List<Articulo> lista = PersistenciaArticulo.mostrarMejorValoradas();
        if (lista.isEmpty()) {
            System.out.println("No hay novedades de este año");
        } else {
            Iterator it = lista.iterator();
            while (it.hasNext()) {
                Articulo art = (Articulo) it.next();
                if (art instanceof Pelicula) {
                    Pelicula p = (Pelicula) art;
                    System.out.println(p.toString());
                }
            }
        }
    }

    /**
     * Recorre la lista de articulos seleccionados para el alquiler y los muestra
     * @param lista de artículos creada en la Vista 
     */
    public static void mostrarArticulosSeleccionadas(List<Alquiler> lista) {
        Iterator it = lista.iterator();
        System.out.println("Articulos seleccionadas: ");
        System.out.println("-------------------------------------------");
        while (it.hasNext()) {
            Alquiler a = (Alquiler) it.next();
            Articulo art = (Articulo) a.getArticulo();
            System.out.println(art.toString());
        }
    }
    /**
     * Carga una lista de artículos a través de la Persistencia de Articulo cuyo año es el actual 
     */
    public static void mostrarNovedades() {
        List<Articulo> lista = PersistenciaArticulo.mostrarNovedades();
        if (lista.isEmpty()) {
            System.out.println("No hay peliculas de este año");
        } else {
            Iterator it = lista.iterator();
            while (it.hasNext()) {
                Pelicula p = (Pelicula) it.next();
                System.out.println(p.toString());
            }
        }
    }
    /**
     * Añade un nuevo articulo a la lista de articulos preseleccionados por el cliente
     * Recibe el codigo y crea el objeto a partir de la Persistencia
     * @param listaAlquileres con los articulos previamente escogidos
     * @param codigo del nuevo artículo seleccionado
     */
    public static void AddAlquiler(List<Alquiler> listaAlquileres, int codigo) {
        try {
            Articulo a = PersistenciaArticulo.obtenerArticulo(codigo);
            if (a == null) {
                System.out.println("No existe ningun articulo con dicho id");
            } else if (a.isDisponible()) {
                Date fechaActual = new Date();
                long fecha = fechaActual.getTime() + (a.getTarifa().getDiasAlquiler()) * Timer.ONE_DAY;
                Date fechaDevolucion = new Date(fecha);
                Alquiler alq = new Alquiler(fechaActual, fechaDevolucion, a, a.getTarifa().getPrecioAlquiler());
                listaAlquileres.add(alq);
                PersistenciaArticulo.preseleccionarArticulo(a);
                System.out.println("Articulo añadido correctamente al CARRITO");
            } else {
                System.out.println("El articulo introducido no se encuentra disponible");
            }
        } catch (Exception ex) {
            Logger.getLogger(GestionAlquiler.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Elimina un articulo de la lista de articulos preseleccionados por el cliente
     * Recibe el codigo, llama a la Persistencia y crea un objeto
     * @param listaAlquileres 
     * @param codigo del articulo a eliminar
     */
    public static void EliminarAlquiler(List<Alquiler> listaAlquileres, int codigo) {
        Articulo a = PersistenciaArticulo.obtenerArticulo(codigo);
        if (a == null) {
            System.out.println("No existe ningun articulo con dicho id");
        }
        Iterator it = listaAlquileres.iterator();
        Alquiler alq = null;
        while (it.hasNext()) {
            alq = (Alquiler) it.next();
            if (alq.getArticulo().equals(a)) {
                it.remove();
                PersistenciaArticulo.deseleccionaArticulo(alq.getArticulo());
            }
        }
        System.out.println("Articulo eliminado correctamente del CARRITO");
    }

    /**
     * Aplica tanto el porcentaje de descuento como los dias extra asociados a la promocion a aplicar
     * @param Alquiler sobre el cual se aplica la promocion
     * @param promocion a aplicar sobre el alquiler
     */
    public static void aplicacionPromocion(Alquiler a, Promocion promo) {
        //Comprueba si la fecha Fin Alquiler coincide con los dias de la Promocion, si no modifica la fecha Fin Alquiler
        if (promo.getDias() != 0) {
            Date fechaActual = a.getFechaFin();
            long fecha = fechaActual.getTime() + (promo.getDias()) * Timer.ONE_DAY;
            Date nuevaFecha = new Date(fecha);
            a.setFechaFin(nuevaFecha);
        }
        //Comprueba si porcentaje de Promocion es > 0, y modifica el Precio de Alquiler
        if (promo.getPorcentaje() != 0) {
            float precio = a.getPrecio();
            a.setPrecio(precio - (precio * (promo.getPorcentaje() / 100)));
        }

    }

    /**
     * Carga una lista de promociones a traves de la Persistencia de Promociones
     * Para cada articulo de la lista de alquileres recorre la lista de promociones revisando si el articulo
     * cumple los requisitos de la promocion.
     * Si los cumple llama al método aplicacionPromocion pasandole el alquiler y la promocion
     * Ademas añade la promocion a una lista de promociones del alquiler para su impresión en una posterior factura
     * @param lista de alquileres sobre la cual comprobar si cumple algunas de las promociones existentes
     */
    public static void comprobarPromociones(List<Alquiler> lista) {
        List<Promocion> listaPromociones = PersistenciaPromocion.mostrarPromocionesVigentes();
        for (Alquiler a : lista) {
            if (a.getArticulo() instanceof Pelicula) {
                Pelicula peli = (Pelicula) a.getArticulo();
                for (Promocion promo : listaPromociones) {
                    if (promo.esAño() && peli.getAnyo() == Integer.parseInt(promo.getDescripcionTipo())) {
                        a.getListap().add(promo);
                        aplicacionPromocion(a, promo);
                    }
                    if (promo.esDirector() && peli.getDirector().compareTo(promo.getDescripcionTipo()) == 0) {
                        a.getListap().add(promo);
                        aplicacionPromocion(a, promo);
                    }
                    if (promo.esGenero() && peli.getGenero().compareTo(promo.getDescripcionTipo()) == 0) {
                        a.getListap().add(promo);
                        aplicacionPromocion(a, promo);
                    }
                    if (promo.esDias() && Calendar.getInstance().getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.getDefault()).compareToIgnoreCase(promo.getDescripcionTipo()) == 0) {
                        a.getListap().add(promo);
                        aplicacionPromocion(a, promo);
                    }

                }
            }
            if (a.getArticulo() instanceof Juego) {
                Juego juego = (Juego) a.getArticulo();
                for (Promocion promo : listaPromociones) {
                    if (promo.esGenero() && juego.getGenero().compareTo(promo.getDescripcionTipo()) == 0) {
                        a.getListap().add(promo);
                        aplicacionPromocion(a, promo);
                    }
                    if (promo.esSoporte() && juego.getSoporte().compareTo(promo.getDescripcionTipo()) == 0) {
                        a.getListap().add(promo);
                        aplicacionPromocion(a, promo);
                    }
                    if (promo.esDias() && Calendar.getInstance().getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.getDefault()).compareToIgnoreCase(promo.getDescripcionTipo()) == 0) {
                        a.getListap().add(promo);
                        aplicacionPromocion(a, promo);
                    }
                }
            }
        }
    }

    /**
     * Confirma una lista de peliculas seleccionadas para el alquiler.
     * Comprueba las promociones aplicables a través del método comprobarPromociones
     * Crea una factura de alquiler
     * Descuenta el saldo correspondiente al cliente en caso de que sea suficiente
     * @param cliente sobre el que realizar el alquiler
     * @param listaAlquileres de artículos seleccionados para el alquiler
     * @param dependiente que ha realizado el alquiler a traves de la tienda
     */
    public static void confirmar(Cliente c, List<Alquiler> listaAlquileres, Empleado dependiente) {
        if (!listaAlquileres.isEmpty()) {
            comprobarPromociones(listaAlquileres);
            FacturaAlquiler f = new FacturaAlquiler(c, new Date(), listaAlquileres, dependiente);
            if (c.getSaldo() >= f.getTotal()) {
                f.imprimirFactura();
                PersistenciaFactura.insertarFacturaAlquiler("Alquiler", f);
                System.out.println("Alquiler descontado automaticamente de su cuenta");
                GestionMovimientos.addMovimiento(c, -f.getTotal(), "Alquiler");
                GestionSaldo.recargarSaldo(-f.getTotal(), c);
                System.out.println("Su saldo actual es de: " + c.getSaldo());
                PersistenciaAlquiler.crearAlquiler(c, listaAlquileres);
                listaAlquileres.removeAll(listaAlquileres);
            } else {
                System.out.println("Su saldo no es suficiente para el alquiler");
                System.out.println("Recargue su cuenta");
                Iterator it = listaAlquileres.iterator();
                while (it.hasNext()) {
                    Alquiler alq = (Alquiler) it.next();
                    PersistenciaArticulo.deseleccionaArticulo(alq.getArticulo());
                    it.remove();
                }

            }
        } else {
            System.out.println("No ha seleccionado ningun artículo");
        }
    }
    /**
     * Método redefinido para su uso en el cajero sin dependiente
     * Confirma una lista de peliculas seleccionadas para el alquiler.
     * Comprueba las promociones aplicables a través del método comprobarPromociones
     * Crea una factura de alquiler
     * Descuenta el saldo correspondiente al cliente en caso de que sea suficiente
     * @param cliente sobre el que realizar el alquiler
     * @param listaAlquileres de artículos seleccionados para el alquiler
     * 
     */
    public static void confirmar(Cliente c, List<Alquiler> listaAlquileres) {
        comprobarPromociones(listaAlquileres);
        FacturaAlquiler f = new FacturaAlquiler(c, new Date(), listaAlquileres);
        if (c.getSaldo() >= f.getTotal()) {
            f.imprimirFactura();
            PersistenciaFactura.insertarFacturaAlquiler("Alquiler", f);
            System.out.println("Alquiler descontado automaticamente de su cuenta");
            GestionMovimientos.addMovimiento(c, -f.getTotal(), "Alquiler");
            GestionSaldo.recargarSaldo(-f.getTotal(), c);
            System.out.println("Su saldo actual es de: " + c.getSaldo());
            PersistenciaAlquiler.crearAlquiler(c, listaAlquileres);
            listaAlquileres.removeAll(listaAlquileres);
        } else {
            System.out.println("Su saldo no es suficiente para el alquiler");
            System.out.println("Recargue su cuenta");
            Iterator it = listaAlquileres.iterator();
            while (it.hasNext()) {
                Alquiler alq = (Alquiler) it.next();
                PersistenciaArticulo.deseleccionaArticulo(alq.getArticulo());
                it.remove();
            }

        }
    }

    /**
     * Verifica que al salir del menu sin haber confirmado que los artículos seleccionados se pongan a disponibles de nuevo
     * @param lista de artículos previamente seleccionados
     */
    public static void salirSinConfirmar(List<Alquiler> lista) {
        Iterator it = lista.iterator();
        while (it.hasNext()) {
            Alquiler a = (Alquiler) it.next();
            Articulo art = a.getArticulo();
            PersistenciaArticulo.deseleccionaArticulo(art);
            it.remove();
        }
    }
    /**
     * Busca articulos que coincidan con el genero
     * @param genero 
     */
    public static void busquedaGenero(String genero) {
        List<Articulo> lista = PersistenciaArticulo.obtenerArticulos("genero", genero);
        Iterator it = lista.iterator();
        while (it.hasNext()) {
            Articulo a = (Articulo) it.next();
            System.out.println(a.toString());
        }
    }
    /**
     * Busca peliculas que coincidan en el titulo
     * @param titulo 
     */
    public static void busquedaPeliculaTitulo(String titulo) {
        List<Articulo> lista = PersistenciaArticulo.obtenerArticulos("titulo", titulo);
        Iterator it = lista.iterator();
        while (it.hasNext()) {
            Articulo a = (Articulo) it.next();
            if (a instanceof Pelicula) {
                System.out.println(a.toString());
            }
        }
    }
    /**
     * Busca peliculas que coincidan en el año
     * @param anyo 
     */
    public static void busquedaAnyo(int anyo) {
        List<Articulo> lista = PersistenciaArticulo.obtenerArticulos("ano", Integer.toString(anyo));
        Iterator it = lista.iterator();
        while (it.hasNext()) {
            Articulo a = (Articulo) it.next();
            System.out.println(a.toString());
        }
    }
    /**
     * Busca peliculas que coincidan en el director
     * @param director 
     */
    public static void busquedaDirector(String director) {
        List<Articulo> lista = PersistenciaArticulo.obtenerArticulos("director", director);
        Iterator it = lista.iterator();
        while (it.hasNext()) {
            Articulo a = (Articulo) it.next();
            System.out.println(a.toString());
        }
    }
    /**
     * Busca juegos que coincidan en el genero
     * @param genero 
     */
    public static void busquedaJuegoGenero(String genero) {
        List<Articulo> lista = PersistenciaArticulo.obtenerArticulos("genero", genero);
        Iterator it = lista.iterator();
        while (it.hasNext()) {
            Articulo a = (Articulo) it.next();
            System.out.println(a.toString());
        }
    }
    /**
     * Busca juegos que coincidan en el titulo escogido
     * @param titulo 
     */
    public static void busquedaJuegoTitulo(String titulo) {
        List<Articulo> lista = PersistenciaArticulo.obtenerArticulos("titulo", titulo);
        Iterator it = lista.iterator();
        while (it.hasNext()) {
            Articulo a = (Articulo) it.next();
            if (a instanceof Juego) {
                System.out.println(a.toString());
            }
        }
    }
    /**
     * Busca juegos que coincidan con el soporte
     * @param soporte 
     */
    public static void busquedaJuegoSoporte(String soporte) {
        List<Articulo> lista = PersistenciaArticulo.obtenerArticulos("soporte", soporte);
        Iterator it = lista.iterator();
        while (it.hasNext()) {
            Articulo a = (Articulo) it.next();
            System.out.println(a.toString());
        }
    }
}
